package org.activequant.data.util.series;

import java.util.Iterator;

import org.activequant.core.domainmodel.SeriesSpecification;
import org.activequant.core.domainmodel.data.MarketDataEntity;
import org.activequant.data.retrieval.ISeriesDataIteratorSource;

/**
 * Generic data iterator source proxy. Use it to implement misc transformations (lag, scale, etc)
 * of the data.<br/>
 * An abstract class. TransformingDataIteratorSourceBase&lt;T extends MarketDataEntity&lt;T&gt;&gt; implements ISeriesDataIteratorSource&lt;T&gt;.<br/>
 * Holds the following associated variables:
 * <ul>
 * <li>vendor(String)</li>
 * <li>source(ISeriesDataIteratorSource&lt;T&gt;)</li>
 * </ul>
 * <p>
 * <b>History:</b><br>
 *  - [13.01.2008] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
public abstract class TransformingDataIteratorSourceBase<T extends MarketDataEntity<T>> implements ISeriesDataIteratorSource<T> {
	/**
	 * private final String vendor;
	 */
	private final String vendor;
	/**
	 * private final ISeriesDataIteratorSource&lt;T&gt; source;
	 */
	private final ISeriesDataIteratorSource<T> source;
	/**
	 * constructs a TransformingDataIteratorSourceBase&lt;T extends MarketDataEntity&lt;T&gt;&gt;(implements ISeriesDataIteratorSource&lt;T&gt;) using the given
	 * vendor(String) and source(ISeriesDataIteratorSource&lt;T&gt;) to set its associated vendor(String) and source(ISeriesDataIteratorSource&lt;T&gt;)
	 * @param vendor
	 * @param source
	 */
	public TransformingDataIteratorSourceBase(String vendor, ISeriesDataIteratorSource<T> source) {
		this.vendor = vendor;
		this.source = source;
	}
	
	/**
	 * Override this to provide transformation of the data items.<br/>
	 * An abstract method
	 * @param item input item (never null).
	 * @return output item (must never be null).
	 */
	protected abstract T transformDataItem(T item);
	/**
	 * Gets an iterator for the market events fetched for the given seriesSpecification(SeriesSpecification) from the associated source(ISeriesDataIteratorSource&lt;T&gt;).<br/>
	 * Creates and returns an Iterable&lt;T&gt; for those market events which invokes the abstract <code>transformDataItem(next)</code> on every element before returning it.
	 */
	public Iterable<T> fetch(final SeriesSpecification seriesSpecification) throws Exception {
		
		final Iterator<T> iterator = source.fetch(seriesSpecification).iterator();

		return new Iterable<T>() {

			public Iterator<T> iterator() {
				return new Iterator<T>() {

					public boolean hasNext() {
						return iterator.hasNext();
					}

					public T next() {
						T next = iterator.next();
						
						if(next == null) {
							return null;
						}
						
						next = transformDataItem(next);
						if(next == null) {
							throw new AssertionError("violation of transformation contract: transformation of not-null input shout never result in a null item.");
						}
						
						return next;
					}

					public void remove() {
						throw new UnsupportedOperationException();
					}
					
				};
			}
			
		};
	}
	/**
	 * returns the associated vendor(String)
	 * @return
	 */
	public String getVendorName() {
		return vendor;
	}

}
